﻿/*****************************************************************************
	SNEGA STG GAME ENGINE 0.7a
	Copyright (C) 2009, Xiaohan Tian (snega0223)
	
	http://code.google.com/p/sng-actionscript-stg-engine/
	
	This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License(LGPL) as
	published by the Free Software Foundation, either version 3 of the 
	License, or(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.
	
	You should have received a copy of the GNU Lesser General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/

package com.sng.stg.game 
{
	import away3d.cameras.*;
	import away3d.containers.*;
	import away3d.core.base.Object3D;
	import away3d.core.math.*;
	import away3d.core.utils.*;
	import away3d.primitives.Sphere;
	import com.sng.stg.game.bullet.EnemyBullet;
	import com.sng.stg.game.enemy.Enemy;
	import com.sng.stg.game.event.ContinuousEvent;
	import com.sng.stg.game.event.GameEvent;
	import com.sng.stg.game.Player.Player;
	
	import com.sng.stg.game.bullet.PlayerBullet;
	
	import flash.display.*;
	import flash.events.*;
	import flash.text.TextField;
	import flash.text.TextFormat;
	
	/**
	 * ...
	 * @author snega
	 */
	public class StageViewer extends Sprite
	{
		public static var PI:Number = 3.141592653589793;
		
		public static var KEY_UP:int = 38;
		public static var KEY_DOWN:int = 40;
		public static var KEY_LEFT:int = 37;
		public static var KEY_RIGHT:int = 39;
		public static var KEY_Z:int = 90;
		public static var KEY_X:int = 88;
		public static var KEY_LSHIFT:int = 16;
		
		public var _keyboardStatus:Array = new Array(256);
		
		protected var _cameraRotX:Number = 0, _cameraRotY:Number = 0;
		protected var _cameraDis:Number = 1500;
		protected var _cameraTarget:Number3D = new Number3D(0, 0, 0);		
		
		protected var _scene:Scene3D;
		protected var _camera:Camera3D;
		protected var _view:View3D;
		
		/* element */
		protected var _elements:ObjectContainer3D = null;
		protected var _elemtntZLength:Number = 0;
		
		protected var _offsetPerFrame:Number3D = new Number3D(0, 0, 0);
		protected var _offsetLimiter:Number3D = new Number3D(0, 0, 0);
		
		protected var _3dFrameSkip:int = 2;
		protected var _3dFrame:int = 0;
		
		/* 2D element */
		public var _background:Sprite = new Sprite();
		public var _viewMask:Sprite = new Sprite();
		public var _2dElement:Sprite = new Sprite();
		public var _2dMask:Sprite = new Sprite();
		
		/* player */
		public var _player:Player = null;
		protected var _playerBullet:Bitmap = null;
		protected var _playerBulletData:BitmapData = null;
		
		public var _playerBullentList:PlayerBullet = new PlayerBullet(null);
		
		public var _playerEnable:Boolean = true;
		
		/* scoreboard */
		public var _scoreboard:Sprite = new Sprite();
		public var _scoreboardFormat:TextFormat = new TextFormat();
		public var _playerPoint:TextField = new TextField();
		public var _playerLife:TextField = new TextField();
		public var _playerGraze:TextField = new TextField();
		public var _playerBomb:TextField = new TextField();
		
		/* static models */
		public var _modelMap:Object = new Object();
		
		/* static images */
		public var _imageBitmapMap:Object = new Object();
		
		/* enemy */
		public var _currEnemyList:Enemy = new Enemy();
		public var _enemyBulletList:EnemyBullet = new EnemyBullet(null);
		
		/* event */
		protected var _eventList:GameEvent = new GameEvent(0);
		protected var _currEvent:GameEvent = null;
		
		public var _continuousEventList:ContinuousEvent = new ContinuousEvent();
		
		/* time */
		public var _time:int = 0;
		public var _frame:int = 0;
		
		public function StageViewer(width:Number = 390, height:Number = 512, zoom:Number = 10, focus:Number = 100, _cameraTarget:Number3D = null, _cameraDis:Number = 1500, _cameraRotX:Number = 0, _cameraRotY:Number = 0) 
		{
			this.addChild(this._background);
			
			this._scene = new Scene3D();
			this._camera = new Camera3D( { zoom:zoom, focus:focus, x:0, y:0, z:this._cameraRotY } );
			
			this._camera.lookAt(this._cameraTarget);
			
			this._view = new View3D( { scene:this._scene, camera:this._camera } );
			this._view.x = width / 2;
			this._view.y = height / 2;
			this.addChild(this._view);
			
			this.addChild(this._viewMask);
			this.addChild(this._2dElement);
			this.addChild(this._scoreboard);
			this.addChild(this._2dMask);
			
			if (_cameraTarget != null) {
				this._cameraTarget = _cameraTarget;
			}
			
			this._cameraRotY = _cameraRotY;
			this._cameraRotX = _cameraRotX;
			this._cameraDis = _cameraDis;
			
			this.init3d();
			this.init2d();
			
			// create scoreboard
			this._scoreboardFormat.font = "Palatino Linotype";
			this._scoreboardFormat.color = 0xFFFFFF;
			
			this._playerPoint.x = 10;
			this._playerLife.x = 100;
			this._playerBomb.x = 190;
			this._playerGraze.x = 280;
			
			this._playerPoint.y = 10;
			this._playerLife.y = 10;
			this._playerBomb.y = 10;
			this._playerGraze.y = 10;
			
			this._playerPoint.width = 100;
			this._playerLife.width = 100;
			this._playerBomb.width = 100;
			this._playerGraze.width = 100;
			
			// register listener
			stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
			stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
		}
		
		public function reset():void {
			
		}
		
		public function reload(url:String = null):void {
			
		}
		
		protected function init3d():void {
			// init camera
			if (_cameraRotY > PI * 64 / 2) _cameraRotY = PI * 64 / 2;
			if (_cameraRotY < 0) _cameraRotY = 0;
				
			this._camera.y = _cameraDis * Math.sin(_cameraRotY / 64);
			this._camera.x = _cameraDis * Math.sin(_cameraRotX / 64) * Math.cos(_cameraRotY / 64);
			this._camera.z = _cameraDis * Math.cos(_cameraRotX / 64) * Math.cos(_cameraRotY / 64);
			
			this._camera.lookAt(this._cameraTarget);
		}
		
		protected function init2d():void {
			this._scoreboard.addChild(this._playerPoint);
			this._scoreboard.addChild(this._playerLife);
			this._scoreboard.addChild(this._playerBomb);
			this._scoreboard.addChild(this._playerGraze);
		}
		
		public function onKeyDown( event:KeyboardEvent ):void {
			this._keyboardStatus[event.keyCode] = true;
		}
		
		public function onKeyUp( event:KeyboardEvent ):void {
			this._keyboardStatus[event.keyCode] = false;
		}
		
		protected function start():void {
			this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
			
			this._player.x = 195;
			this._player.y = 491;
			
			this._2dElement.addChild(this._player);
			
			this._time = 0;
			this._frame = 0;
			
			this._currEvent = this._eventList._next;
		}
		
		protected function setElement(o:Object3D, repeatForward:Number = 1, repeatBackward:Number = 1, posOffsetFix:Number3D = null):void {
			//trace(o.maxZ - o.minZ);
			//this._elemtntZLength = (o.maxZ - o.minZ) / 2;
			this._elements = new ObjectContainer3D();
			
			this._offsetLimiter.z = this._elemtntZLength;
			trace(this._elemtntZLength);
			
			for (var i:int = 1; i <= repeatForward; i++) {
				var o2:Object3D = o.clone();
				o2.z += this._elemtntZLength * i;
				
				if (posOffsetFix != null) {
					o2.x += posOffsetFix.x;
					o2.y += posOffsetFix.y;
					o2.z += posOffsetFix.z;
				}
				
				this._elements.addChild(o2.clone());
			}
			
			for (i = 1; i <= repeatBackward; i++) {
				o2 = o.clone();
				o2.z -= this._elemtntZLength * i;
				
				if (posOffsetFix != null) {
					o2.x += posOffsetFix.x;
					o2.y += posOffsetFix.y;
					o2.z += posOffsetFix.z;
				}
				
				this._elements.addChild(o2.clone());
			}
			
			if (posOffsetFix != null) {
				o.x += posOffsetFix.x;
				o.y += posOffsetFix.y;
				o.z += posOffsetFix.z;
			}
			this._elements.addChild(o.clone());
			this._view.scene.addChild(this._elements);
		}
		
		protected function processFrame():void {
			// Process any movement or animation here.
		}
		
		protected function onEnterFrame( ThisEvent:Event ):void {
			var i:int = 0, j:int = 0;
			
			/* 3d element */
			if (++this._3dFrame == this._3dFrameSkip) {
				this._3dFrame = 0;
				
				this._elements.x += this._offsetPerFrame.x * this._3dFrameSkip;
				this._elements.y += this._offsetPerFrame.y * this._3dFrameSkip;
				this._elements.z += this._offsetPerFrame.z * this._3dFrameSkip;
				
				//if (this._elements.x > this._offsetLimiter.x) this._elements.x -= this._offsetLimiter.x;
				//if (this._elements.y > this._offsetLimiter.y) this._elements.y -= this._offsetLimiter.y;
				if (this._elements.z > this._offsetLimiter.z) this._elements.z -= this._offsetLimiter.z;		
				
				if (_cameraRotY > PI * 64 / 2) _cameraRotY = PI * 64 / 2;
				if (_cameraRotY < 0) _cameraRotY = 0;
					
				this._camera.y = _cameraDis * Math.sin(_cameraRotY / 64);
				this._camera.x = _cameraDis * Math.sin(_cameraRotX / 64) * Math.cos(_cameraRotY / 64);
				this._camera.z = _cameraDis * Math.cos(_cameraRotX / 64) * Math.cos(_cameraRotY / 64);
				
				this._camera.lookAt(this._cameraTarget);
				
				this._view.render();	
			}
			
			/* player bullets */
			var playerBullet:PlayerBullet = this._playerBullentList._next, newPlayerBullet:PlayerBullet = null;
			while (playerBullet != null) {				
				// process y-axe
				playerBullet.process();
				
				// only check y-axe
				if (playerBullet.y < -20) {
					playerBullet.remove();
					this._2dElement.removeChild(playerBullet);
				}
				
				playerBullet = playerBullet._next;
			}
			
			/* player */
			if (this._playerEnable) {
				if (this._keyboardStatus[StageViewer.KEY_UP]) {
					if (this._keyboardStatus[StageViewer.KEY_LSHIFT]) {
						this._player.y -= 1;
					}
					else {
						this._player.y -= 4;
					}
				}
				
				if (this._keyboardStatus[StageViewer.KEY_DOWN]) {
					if (this._keyboardStatus[StageViewer.KEY_LSHIFT]) {
						this._player.y += 1;
					}
					else {
						this._player.y += 4;
					}
				}
				
				if (this._keyboardStatus[StageViewer.KEY_LEFT]) {
					if (this._keyboardStatus[StageViewer.KEY_LSHIFT]) {
						this._player.x -= 1;
					}
					else {
						this._player.x -= 4;
					}
				}
				
				if (this._keyboardStatus[StageViewer.KEY_RIGHT]) {
					if (this._keyboardStatus[StageViewer.KEY_LSHIFT]) {
						this._player.x += 1;
					}
					else {
						this._player.x += 4;
					}
				}
				
				if (this._player.x < 0) this._player.x = 0;
				if (this._player.x > 366) this._player.x = 366;
				if (this._player.y < 0) this._player.y = 0;
				if (this._player.y > 479) this._player.y = 479;
				
				// player fire
				if (this._keyboardStatus[StageViewer.KEY_Z]) {
					newPlayerBullet = new PlayerBullet(this, this._playerBulletData);
					newPlayerBullet.x = this._player.x - 10;
					newPlayerBullet.y = this._player.y - 16;
					
					this._playerBullentList.push(newPlayerBullet);
					
					this._2dElement.addChild(newPlayerBullet);
					
					newPlayerBullet = new PlayerBullet(this, this._playerBulletData);
					newPlayerBullet.x = this._player.x + 2;
					newPlayerBullet.y = this._player.y - 16;
					
					this._playerBullentList.push(newPlayerBullet);
					
					this._2dElement.addChild(newPlayerBullet);
				}
			}
			
			// enemy
			var enemy:Enemy = this._currEnemyList._next;
			while (enemy != null) {
				enemy.process();
				enemy = enemy._next;
			}
			
			// enemy bullets
			var enemyBullet:EnemyBullet = this._enemyBulletList._next;
			while (enemyBullet != null) {
				enemyBullet.process();
				
				if (enemyBullet.x < -20 || enemyBullet.x > 400 || enemyBullet.y < -20 || enemyBullet.y > 500) {
					this._2dElement.removeChild(enemyBullet);
					enemyBullet.remove();
					this._player._point += 5;
				}
				
				enemyBullet = enemyBullet._next;
			}
			
			// time and event
			this._frame++;
			if (this._frame == 6) {
				this._frame = 0;
				this._time++;
				
				if (this._currEvent != null && this._time == this._currEvent._time) {
					this._currEvent.execute(this);
					this._currEvent = this._currEvent._next;
				}
			}

			// continuous events
			var ce:ContinuousEvent = this._continuousEventList._next;
			while (ce != null) {
				ce.process();
				ce = ce._next;
			}
			
			// scoreboard
			this._playerPoint.text = "score: " + this._player._point;
			this._playerLife.text = "life: " + this._player._life;
			this._playerBomb.text = "bomb: 0";
			this._playerGraze.text = "graze: " + this._player._graze;
			this._playerPoint.setTextFormat(this._scoreboardFormat);
			this._playerLife.setTextFormat(this._scoreboardFormat);
			this._playerBomb.setTextFormat(this._scoreboardFormat);
			this._playerGraze.setTextFormat(this._scoreboardFormat);
			
			// process
			processFrame();

		}
		
	}
	
}